package nfwx.analytics;
import org.json.JSONArray;
import org.json.JSONException;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 采集信息发送队列管理
 */

class GrabSendQueue {

    /**
     * 发送回调接口
     */
    interface SendCallBack
    {
        ///发送成功
        void onOK();
        ///发送失败
        void onFail(Exception e);
    }

    /**
     * 发送队列的IO操作接口, 调用者需要实现这个接口以供队列进行IO操作和网络操作
     */
    interface SendQueueIo
    {
        /**
         * 加载队列接口
         * @return 队列JSON字符串
         */
        String open() throws IOException;
        /**
         * 保存队列接口
         * @param s
         * @throws IOException
         */
        void save(String s) throws IOException;

        /**
         * 发送任务到服务器
         * @param statInfo
         * @param cb
         */
        void send(Map<String, String> statInfo, SendCallBack cb);
    }

    ///IO操作接口
    SendQueueIo _io;
    //发送队列
    List<GrabSend> _tasks;
    //应用ID
    final String _appId;
    //应用密钥
    final String _secret;
    ///是否已经关闭
    boolean _closed;
    ///是否正在提交
    boolean _runnig;

    /**
     * 创建发送队列
     * @param io 调用者实现的IO操作
     * @param appId 应用ID
     * @param secret 应用密钥
     */
    GrabSendQueue(SendQueueIo io, String appId, String secret)
    {
        _appId = appId;
        _secret = secret;
        _tasks = new LinkedList<>();
        _io = io;

        //从本地存储中加载队列
        try {
            String s = _io.open();
            if (s != null && !s.equals("")) {
                JSONArray tasks = new JSONArray(s);
                for (int i = 0; i < tasks.length(); ++i) {
                    _tasks.add(new GrabSend(tasks.getJSONObject(i)));
                }
            }
        } catch(Exception e) { //加载出错，丢弃并清除存储的队列数据
            e.printStackTrace();
            try {
                _io.save("");
            } catch (Exception e2) {
                e2.printStackTrace();
            }
            _tasks.clear();
        }
        if (_tasks.size() != 0) {
            send();
        }
    }

    /**
     * 将会话提交到队列
     * @param session
     * @return
     */
    GrabSendQueue post(GrabSession session) throws JSONException, IOException {
        GrabSend task = new GrabSend(session);
        if (!task.getValid()) return this; //无需提交
        _tasks.add(task);
        if (_tasks.size() > 4096) { //最多4096个任务
            _tasks.remove(0);
        }
        return save();
    }

    /**
     * 保存当前队列
     * @return
     */
    GrabSendQueue save() throws JSONException, IOException {
        JSONArray tasks = new JSONArray();
        for(int i=0; i<_tasks.size(); ++i) {
            tasks.put(_tasks.get(i).toJSON());
        }
        String s=tasks.toString();
        _io.save(s);
        return this;
    }

    /**
     * 获取应用ID
     * @return
     */
    String getAppId()
    {
        return _appId;
    }

    /**
     * 关闭提交
     */
    void close()
    {
        _closed = true;
    }

    /**
     * 触发提交，该函数行为：如果提交失败则整个过程停止，需要外部定时触发调用此函数
     */
    boolean send()
    {
        if (_closed || _runnig) return false;
        if (_tasks.isEmpty()) return false;
        _runnig = true;
        final GrabSend task = _tasks.get(0);
        Map<String, String> params = null;
        try {
            params = task.makeSubmitParams(_appId, _secret);
        } catch (Exception e) {
            e.printStackTrace();
            _runnig = false;
            if (_tasks.get(0) == task) {
                _tasks.remove(0);
            }
            _runnig = false;
            try {
                save();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
            return false;
        }
        try {
            save();
        } catch (Exception e2) {
            e2.printStackTrace();
        }
        _io.send(params, new SendCallBack() {
            @Override
            public void onOK() {
                if (!_tasks.isEmpty() && _tasks.get(0) == task) {
                    _tasks.remove(0);
                    try {
                        save();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                _runnig = false;
                send();
            }

            @Override
            public void onFail(Exception e) {
                e.printStackTrace();
                _runnig = false;
            }
        });
        return true;
    }

}
